/**
  ******************************************************************************
  * @file    bsp_led.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   SPI sd卡测试驱动（不含文件系统）
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F103-MINI 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
#include "sdcard_test.h"

#include "ff.h"

#include "bsp.h"

extern uint8_t  SD_Type;
extern SD_CardInfo SDCardInfo;
/* Private typedef -----------------------------------------------------------*/
typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;

/* Private define ------------------------------------------------------------*/
#define BLOCK_SIZE            512 /* Block Size in Bytes */

#define NUMBER_OF_BLOCKS      10  /* For Multi Blocks operation (Read/Write) */
#define MULTI_BUFFER_SIZE    (BLOCK_SIZE * NUMBER_OF_BLOCKS)


/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t Buffer_Block_Tx[BLOCK_SIZE], Buffer_Block_Rx[BLOCK_SIZE];
uint8_t Buffer_MultiBlock_Tx[MULTI_BUFFER_SIZE], Buffer_MultiBlock_Rx[MULTI_BUFFER_SIZE];
volatile TestStatus EraseStatus = FAILED, TransferStatus1 = FAILED, TransferStatus2 = FAILED;
SD_Error Status = SD_RESPONSE_NO_ERROR;

/* Private function prototypes -----------------------------------------------*/
static void SD_SingleBlockTest(void);
void SD_MultiBlockTest(void);
static void Fill_Buffer(uint8_t *pBuffer, uint32_t BufferLength, uint32_t Offset);
static TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength);

/* Private functions ---------------------------------------------------------*/

FATFS fs;                         /* FatFs文件系统对象 */
FIL fnew;                         /* 文件对象 */
FRESULT res_sd;                /* 文件操作结果 */
UINT fnum;                        /* 文件成功读写数量 */
BYTE ReadBuffer[1024]= {0};       /* 读缓冲区 */
BYTE WriteBuffer[] =  "欢迎使用野火STM32开发板 今天是个好日子，新建文件系统测试文件\r\n";            /* 写缓冲区*/

void show_sdcard_info(void)
{
	switch(SD_Type)
	{
		case SD_TYPE_V1:printf("Card Type:SDSC V1.1\r\n");break;
		case SD_TYPE_V2:printf("Card Type:SDSC V2.0\r\n");break;
		case SD_TYPE_V2HC:printf("Card Type:SDHC V2.0\r\n");break;
		// case SDIO_MULTIMEDIA_CARD:printf("Card Type:MMC Card\r\n");break;
	}
    printf("\r\nSD卡信息\r\n");
  	printf("Card ManufacturerID:%d\r\n",SDCardInfo.SD_cid.ManufacturerID);	//制造商ID
		// printf("Card RCA:%d\r\n",SDCardInfo.RCA);								//卡相对地址
		printf("Card Capacity:%d MB\r\n",(u32)(SDCardInfo.CardCapacity>>20));	//显示容量
		printf("Card BlockSize:%d\r\n\r\n",SDCardInfo.CardBlockSize);			//显示块大小
}


void SD_Test(void)
{

	/* SD初始化*/
  if((Status = SD_Init()) != SD_RESPONSE_NO_ERROR)
  {    

    printf("SD init failed \n");
    while(1);
  }
  else
  {
    printf("SD init success \n");		 
    
  }
        
  if(Status == SD_RESPONSE_NO_ERROR) 
  {
    
    /*single block 读写测试*/
    SD_SingleBlockTest();
    
    /*muti block 读写测试*/
    SD_MultiBlockTest();
  }
	
	show_sdcard_info();
}



/**
  * @brief  Tests the SD card Single Blocks operations.
  * @param  None
  * @retval None
  */
void SD_SingleBlockTest(void)
{  
  /*------------------- Block Read/Write --------------------------*/
  /* Fill the buffer to send */
  Fill_Buffer(Buffer_Block_Tx, BLOCK_SIZE, 0x320F);

  if (Status == SD_RESPONSE_NO_ERROR)
  {
    /* Write block of 512 bytes on address 0 */
    Status = SD_WriteBlock(Buffer_Block_Tx, 0x00, BLOCK_SIZE);
    /* Check if the Transfer is finished */
  }

  if (Status == SD_RESPONSE_NO_ERROR)
  {
    /* Read block of 512 bytes from address 0 */
    Status = SD_ReadBlock(Buffer_Block_Rx, 0x00, BLOCK_SIZE);

  }

  /* Check the correctness of written data */
  if (Status == SD_RESPONSE_NO_ERROR)
  {
    TransferStatus1 = Buffercmp(Buffer_Block_Tx, Buffer_Block_Rx, BLOCK_SIZE);
  }
  
  if(TransferStatus1 == PASSED)
  {

    printf("Single block success\n");

  }
  else
  {

    printf("Single block failed \n");
    
  }
}

/**
  * @brief  Tests the SD card Multiple Blocks operations.
  * @param  None
  * @retval None
  */
void SD_MultiBlockTest(void)
{  
  /*--------------- Multiple Block Read/Write ---------------------*/
  /* Fill the buffer to send */
  Fill_Buffer(Buffer_MultiBlock_Tx, MULTI_BUFFER_SIZE, 0x0);

  if (Status == SD_RESPONSE_NO_ERROR)
  {
    /* Write multiple block of many bytes on address 0 */
    Status = SD_WriteMultiBlocks(Buffer_MultiBlock_Tx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
    /* Check if the Transfer is finished */
  }

  if (Status == SD_RESPONSE_NO_ERROR)
  {
    /* Read block of many bytes from address 0 */
    Status = SD_ReadMultiBlocks(Buffer_MultiBlock_Rx, 0x00, BLOCK_SIZE, NUMBER_OF_BLOCKS);
    /* Check if the Transfer is finished */
  }

  /* Check the correctness of written data */
  if (Status == SD_RESPONSE_NO_ERROR)
  {
    TransferStatus2 = Buffercmp(Buffer_MultiBlock_Tx, Buffer_MultiBlock_Rx, MULTI_BUFFER_SIZE);
  }
  
  if(TransferStatus2 == PASSED)
  {
    printf("Multi block success \n");
  }
  else
  {
    printf("Multi block failed \n");
  }
}

/**
  * @brief  Compares two buffers.
  * @param  pBuffer1, pBuffer2: buffers to be compared.
  * @param  BufferLength: buffer's length
  * @retval PASSED: pBuffer1 identical to pBuffer2
  *         FAILED: pBuffer1 differs from pBuffer2
  */
TestStatus Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint32_t BufferLength)
{
  while (BufferLength--)
  {
    if (*pBuffer1 != *pBuffer2)
    {
      return FAILED;
    }

    pBuffer1++;
    pBuffer2++;
  }

  return PASSED;
}

/**
  * @brief  Fills buffer with user predefined data.
  * @param  pBuffer: pointer on the Buffer to fill
  * @param  BufferLength: size of the buffer to fill
  * @param  Offset: first value to fill on the Buffer
  * @retval None
  */
void Fill_Buffer(uint8_t *pBuffer, uint32_t BufferLength, uint32_t Offset)
{
  uint16_t index = 0;

  /* Put in global buffer same values */
  for (index = 0; index < BufferLength; index++)
  {
    pBuffer[index] = index + Offset;
  }
}



void FatFS_Test(void)
{
	//在外部SPI Flash挂载文件系统，文件系统挂载时会对SPI设备初始化

	res_sd = f_mount(&fs,"0:",1);

	/*----------------------- 格式化测试 ---------------------------*/
	/* 如果没有文件系统就格式化创建创建文件系统 */
	if (res_sd == FR_NO_FILESYSTEM) {
			printf("》SD卡还没有文件系统，即将进行格式化...\r\n");
			/* 格式化 */
			res_sd = f_mkfs("0:", NULL , ReadBuffer , sizeof(ReadBuffer));

			if (res_sd == FR_OK) {
					printf("》SD卡已成功格式化文件系统。\r\n");
					/* 格式化后，先取消挂载 */
					res_sd = f_mount(NULL,"0:",1);
					/* 重新挂载 */
					res_sd = f_mount(&fs,"0:",1);
			} else {
					
					printf("《《格式化失败。》》\r\n");
					while (1);
			}
	} else if (res_sd!=FR_OK) {
			printf("！！SD卡挂载文件系统失败。(%d)\r\n",res_sd);
			printf("！！可能原因：SD卡初始化不成功。\r\n");
			while (1);
	} else {
			printf("》文件系统挂载成功，可以进行读写测试\r\n");
	}

	/*--------------------- 文件系统测试：写测试 -----------------------*/
	/* 打开文件，如果文件不存在则创建它 */
	printf("\r\n****** 即将进行文件写入测试... ******\r\n");
	res_sd=f_open(&fnew,"0:FatFs.txt",FA_CREATE_ALWAYS|FA_WRITE);
	if ( res_sd == FR_OK ) {
			printf("》打开/创建FatFs读写测试文件.txt文件成功，向文件写入数据。\r\n");
			/* 将指定存储区内容写入到文件内 */
			res_sd=f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
			/* 实测SPI_SD驱动下写入大于512字节的数据在SD卡里打开会显示乱码，如需写入大量数据使用f_write_co替代上面f_write即可 */
			//res_sd=f_write_co(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
			if (res_sd==FR_OK) {
					printf("》文件写入成功，写入字节数据：%d\n",fnum);
					printf("》向文件写入的数据为：\r\n%s\r\n",WriteBuffer);
			} else {
					printf("！！文件写入失败：(%d)\n",res_sd);
			}
			/* 不再读写，关闭文件 */
			f_close(&fnew);
	} else {
			
			printf("！！打开/创建文件失败。\r\n");
	}

	/*------------------ 文件系统测试：读测试 --------------------------*/
	printf("****** 即将进行文件读取测试... ******\r\n");
	res_sd=f_open(&fnew,"0:FatFs.txt",FA_OPEN_EXISTING|FA_READ);
	if (res_sd == FR_OK) {
			
			printf("》打开文件成功。\r\n");
			res_sd = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
			/* 实测SPI_SD驱动下读取大于512字节的数据在SD卡里打开会显示乱码，如需读取大量数据使用f_read_co替代上面f_read即可 */
			//res_sd = f_read_co(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
			if (res_sd==FR_OK) {
					printf("》文件读取成功,读到字节数据：%d\r\n",fnum);
					printf("》读取得的文件数据为：\r\n%s \r\n", ReadBuffer);
			} else {
					printf("！！文件读取失败：(%d)\n",res_sd);
			}
	} else {
			
			printf("！！打开文件失败。\r\n");
	}
	/* 不再读写，关闭文件 */
	f_close(&fnew);

	/* 不再使用文件系统，取消挂载文件系统 */
	f_mount(NULL,"0:",1);

	res_sd = f_mount(&fs,"0:",1);

	/*----------------------- 格式化测试 ---------------------------*/
	/* 如果没有文件系统就格式化创建创建文件系统 */
	if (res_sd == FR_NO_FILESYSTEM) {
			printf("》SD卡还没有文件系统，即将进行格式化...\r\n");
	}
	
	
	/*------------------ 文件系统测试：读测试 --------------------------*/
	printf("****** 即将进行文件读取测试... ******\r\n");
	res_sd=f_open(&fnew,"0:FatFs.txt",FA_OPEN_EXISTING|FA_READ);
	if (res_sd == FR_OK) {
			
			printf("》打开文件成功。\r\n");
			res_sd = f_read(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
			/* 实测SPI_SD驱动下读取大于512字节的数据在SD卡里打开会显示乱码，如需读取大量数据使用f_read_co替代上面f_read即可 */
			//res_sd = f_read_co(&fnew, ReadBuffer, sizeof(ReadBuffer), &fnum);
			if (res_sd==FR_OK) {
					printf("》文件读取成功,读到字节数据：%d\r\n",fnum);
					printf("》读取得的文件数据为：\r\n%s \r\n", ReadBuffer);
			} else {
					printf("！！文件读取失败：(%d)\n",res_sd);
			}
	} else {
			
			printf("！！打开文件失败。\r\n");
	}
}


/*********************************************END OF FILE**********************/
